﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using KlearTweet.Client.Model;

namespace KlearTweet.Client.DataContainers
{
	// TODO: Multiple selection using mouse & keyboard (+ Selection by click'n'drag? Cf. MSDN "Hit Testing in the Visual Layer")
	// + Simplifications: Change selection like this:
	// SelectedItem { get { return SelectedIndex<0 ? null : this[SelectedIndex]; } }
	// SelectedIndex { get { return SelectedIndexes.Length==0 ? -1 : SelectedIndexes[0]; } }
	// Note: SelectedIndexes is the only DP! (I don't need write access to the others anyway!)
	// SelectedItems { get { return new List().AddRange(using SelectedIndexes); } }
	// Note: Cf. Ctor(): "SelectedItems = observableCollection;"

	// TODO: Replace EmptyListIndicator by a "Header" (TextBox) ala WinLivePhotoGallery? ("x items, y selected ---")
    // TODO: re-Review the current implementation of ListBox in WPF to make them more compatible
	public partial class ListView // Note: Based on code from Silverlight 2 Beta 1 Controls
    {
        private static readonly Stack<ListItem> _entityListItems = new Stack<ListItem>(100); // Used for virtualization

		private IList<UIElement> Items
		{
			get { return ItemsHost.AllChildren; }
		}

		private ListItem this[int i] // Logical indexing using the Source (sorted)
		{
			get
			{
				var entity = _displayedList[i];
				return GetListItemForObject(entity);
			}
		}

		private int IndexOf(ListItem listItem) // Its index is the one of its entity
		{
			return _displayedList.IndexOf(listItem.Entity);
		}

		public int Count
		{
			get { return Items.Count; }
		}


        public Func<IEntity, UIElement> EntityViewProvider; // TODO: Find a better solution


        private IList<IEntity> _displayedList = new List<IEntity>();


        public void SetSource(IEnumerable<IEntity> ItemsSource)
		{
            var newFilteredAndSortedList = new List<IEntity>();
			if (ItemsSource != null)
				foreach (var entity in ItemsSource)
					newFilteredAndSortedList.Add(entity);

			for (int i = Items.Count - 1; i >= 0; i--)
			{
				if (newFilteredAndSortedList.Contains(((ListItem)Items[i]).Entity))
					continue; // Still in the list; keep it
				// TODO: Better: Do not remove immediately; ask the animating panel to "move it outside and fire an event" to remove it + When adding items, if the item was in the RemovalAnimation, make it come back
				ClearContainerForItemOverride(Items[i], null);
				ItemsHost.Remove(Items[i]);
			}

			// Now, we no longer need the old list, so we can replace it
			// We do not replace it before because, when removing items, events are raised which require access to the items in the previous list
			_displayedList = newFilteredAndSortedList;

			for (int i = 0; i < _displayedList.Count; i++)
			{
				var listItem = GetListItemForObject(_displayedList[i]);
				if (listItem == null) // New item, Add
				{
					listItem = //IsItemItsOwnContainerOverride(entity) // Always false here
						//? (ListItem)entity :
						GetContainerForItemOverride();
					PrepareContainerForItemOverride(listItem, _displayedList[i]);
                    ItemsHost.Add(listItem);
				}
				/*else // Old item, move it a little so the user knows it was refreshed
				{
                    ItemsHost.Nudge(listItem);
				}*/
			}

			if (ItemsHost.ChildIndex == null) // Order the ListItems based on the position of their item in the _displayedList
				ItemsHost.ChildIndex = childIndex
					=> Items.IndexOf(this[childIndex]);
            ItemsHost.IsInsideViewport = IsInsideViewport;

			ItemsHost.InvalidateMeasure(); // Update the size & location of the items (some shapes decide the size based on the location)

            if (FocusManager.GetFocusedElement() == ElementScrollViewer)
                GiveFocusToItem(false); // TODO: (Note: Occurs when resizing the browser) Needed because, for some reason, when paging with the keyboard on a View that isn't the MainView, the focus is given to the ScrollViewer which trap further paging keys

            EmptyListIndicator.Visibility = Count == 0 ? Visibility.Visible : Visibility.Collapsed;
        }


        public void ScrollToVerticalTop()
        {
            ElementScrollViewer.ScrollToVerticalOffset(0);
        }

        private bool IsInsideViewport(Rect rect)
        {
            if (ElementScrollViewer.VerticalOffset <= rect.Top
                && rect.Top <= (ElementScrollViewer.VerticalOffset + ElementScrollViewer.ViewportHeight))
                return true; // Top is inside

            if (ElementScrollViewer.VerticalOffset <= rect.Bottom
                && rect.Bottom <= (ElementScrollViewer.VerticalOffset + ElementScrollViewer.ViewportHeight))
                return true; // Bottom is inside

            if (ElementScrollViewer.VerticalOffset >= rect.Top
                && rect.Bottom >= (ElementScrollViewer.VerticalOffset + ElementScrollViewer.ViewportHeight))
                return true; // rect is bigger than the viewport and takes it all

            return false; // Not inside
        }



		private FrameworkElement ElementScrollContentPresenter // TODO: LOW - Use a hack to get it :)
		{
			get
			{
				if (ItemsHost == null || ItemsHost.Parent == null)
					return null;
				return (FrameworkElement) ((FrameworkElement) ItemsHost.Parent).Parent;
			}
		}














		/// <summary>
        /// Gets or sets the index of the first item in the current selection 
        /// or returns negative one (-1) if the selection is empty.
        /// </summary>
        public int SelectedIndex 
        { 
            get { return (int)GetValue(SelectedIndexProperty);}
            set { SetValue(SelectedIndexProperty, value);} 
        }

        /// <summary> 
        /// Identifies the SelectedIndex dependency property.
        /// </summary>
        public static readonly DependencyProperty SelectedIndexProperty = DependencyProperty.Register( 
                "SelectedIndex", typeof(int), typeof(ListView), new PropertyMetadata(OnSelectedIndexChanged));
 
        /// <summary>
        /// Gets or sets the first item in the current selection or returns
        /// null if the selection is empty. 
        /// </summary>
		public ListItem SelectedItem
        {
			get { return (ListItem)GetValue(SelectedItemProperty);} 
            set { SetValue(SelectedItemProperty, value);}
        } 

        /// <summary>
        /// Identifies the SelectedItem dependency property. 
        /// </summary>
        public static readonly DependencyProperty SelectedItemProperty = DependencyProperty.Register(
				"SelectedItem", typeof(ListItem), typeof(ListView), new PropertyMetadata(OnSelectedItemChanged));

        /// <summary> 
        /// Gets the currently selected items.
        /// </summary>
		public IList<ListItem> SelectedItems 
        {
			get { return (IList<ListItem>)GetValue(SelectedItemsProperty);}
			private set { SetValue(SelectedItemsProperty, value); }
        } 
 
        /// <summary>
        /// Identifies the SelectedItems dependency property. 
        /// </summary>
        public static readonly DependencyProperty SelectedItemsProperty = DependencyProperty.Register(
				"SelectedItems", typeof(IList<ListItem>), typeof(ListView), new PropertyMetadata(OnSelectedItemsChanged));

        /// <summary>
        /// Identifies the IsSelectionActive dependency property. 
        /// </summary>
        public static readonly DependencyProperty IsSelectionActiveProperty = DependencyProperty.RegisterAttached(
            "IsSelectionActive", typeof(bool), typeof(ListView), new PropertyMetadata(OnIsSelectionActiveChanged));

        /// <summary> 
        /// Maps objects in the Items collection to the corresponding 
        /// ListItem containers
        /// </summary> 
        private readonly Dictionary<IEntity, ListItem> _objectToEntityListItem = new Dictionary<IEntity, ListItem>();

        /// <summary>
        /// Occurs when the selection of a ListView changes. 
        /// </summary> 
        public event SelectionChangedEventHandler SelectionChanged;

        /// <summary>
        /// Occurs one or more times as content scrolls in the vertical ScrollBar.
        /// </summary> 
	    public event ScrollEventHandler VerticalScroll;

        /// <summary>
        /// Set to true iff the ProcessingSelectionPropertyChange method is executing (to prevent recursion)
        /// </summary> 
        private bool _processingSelectionPropertyChange;

        /// <summary> 
        /// Tracks whether changes to read-only DependencyProperties are allowed. 
        /// </summary>
        private bool _readOnlyDependencyPropertyChangesAllowed;

        /// <summary>
        /// Tracks the ListItem that just lost focus. 
        /// </summary>
        private ListItem _listItemOldFocus;
 
        /// <summary> 
        /// Tracks the ListItem that should get focus when the ListView gets focus
        /// </summary> 
        /// <remarks>
        /// Helps implement WPF's KeyboardNavigation.SetTabOnceActiveElement
        /// which is not present in Silverlight. 
        /// </remarks>
        private ListItem _tabOnceActiveElement;
 
        /// <summary> 
        /// Tracks whether to suppress the next "lost focus" event because it was self-caused.
        /// </summary> 
        private bool _suppressNextLostFocus;

        /// <summary> 
        /// Tracks the index of the focused element.
        /// </summary>
        private int _focusedIndex = -1;
 
        /// <summary>
        /// Gets a value that indicates whether the keyboard focus is within the ListView. 
        /// </summary>
        /// <param name="element">The element from which to read the attached property.</param>
        /// <returns>Value of the property, true if the keyboard focus is within the Selector.</returns> 
        public static bool GetIsSelectionActive(DependencyObject element)
        {
            if (null == element) 
            { 
                throw new ArgumentNullException("element");
            } 
            return (bool)element.GetValue(IsSelectionActiveProperty);
        }
 
        /// <summary>
        /// Sets a value that indicates whether the keyboard focus is within the ListView.
        /// </summary> 
        /// <param name="element">The element on which to set the attached property.</param> 
        /// <param name="value">The value to set.</param>
        private static void SetIsSelectionActive(DependencyObject element, bool value) 
        {
            var listView = element as ListView;
            Debug.Assert(null != listView);
            Debug.Assert(!listView._readOnlyDependencyPropertyChangesAllowed);
            try
            { 
                listView._readOnlyDependencyPropertyChangesAllowed = true;
                listView.SetValue(IsSelectionActiveProperty, value);
            } 
            finally
            {
                listView._readOnlyDependencyPropertyChangesAllowed = false;
            }
        }
 
        /// <summary> 
        /// Initializes a new instance of the ListView class.
        /// </summary> 
		public ListView()
		{
			InitializeComponent();

#if WPF 
            KeyboardNavigation.SetDirectionalNavigation(this, KeyboardNavigationMode.Contained);
            KeyboardNavigation.SetTabNavigation(this, KeyboardNavigationMode.Once);
            Focusable = true;
#else 
            // DirectionalNavigation not supported by Silverlight
            TabNavigation = KeyboardNavigationMode.Once;
            // Focusable not supported by Silverlight
#endif
            IsTabStop = false;
            GotFocus += (s, e) => OnGotFocus(e);
            LostFocus += (s, e) => OnLostFocus(e);

            ItemsHost.KeyDown += (s, e) => OnKeyDownInItemsHost(e); // Intercept it before the ScrollViewer gets it :)
            ItemsHost.MouseLeftButtonDown += (s, e) => FocusGivenByUserAction(e);

            // Register MouseWheel for scrolling + add support for VerticalScroll event
            ElementScrollViewer.MouseWheel += (s, e) => RaiseVerticalScroll(this, new ScrollEventArgs( // TODO: This solution might not work well (the event will be triggered before the vOffset is updated)
                ScrollEventType.ThumbPosition, ElementScrollViewer.VerticalOffset));
            ElementScrollViewer.SetIsMouseWheelScrollingEnabled(true);
            LayoutUpdated += (s, e) => RegisterVerticalScroll();

			var observableCollection = new ObservableCollection<ListItem>();
            observableCollection.CollectionChanged += OnSelectedItemsCollectionChanged;
            SelectedItems = observableCollection;
            SelectedIndex = -1;
        }

	    private void OnKeyDownInItemsHost(KeyEventArgs e)
        {
            // TODO: Check all usage of ScrollViewer & wire its host to here because when one of the items has focus, its ScrollViewer intercept the keys
            if (e.OriginalSource is Thumb
                && (e.Key == Key.Left || e.Key == Key.Right)) // TODO: LOW - Might be confusing for the user if these two don't work and the rest works (when he doesn't know that the focus is on the Thumb)
                return;

            if (e.OriginalSource is TextBox)
                return; // Don't handle

            ProcessKeyDown(e);
	    }

	    private void FocusGivenByUserAction(MouseButtonEventArgs e)
        {
            // Allow the user to click on an empty space (instead of an item) and start scrolling/key-navigating
            // Called On ItemsHost.MouseLeftButtonDown
            if (Count == 0)
                return; // Not needed
            if(e.OriginalSource != ItemsHost)
                return; // Clicked on an item inside

            e.Handled = true; // Don't let it propagate otherwise, the ScrollViewer will take the focus
            GiveFocusToItem(true);
        }


	    private void GiveFocusToItem(bool deselectItem)
        {
            if (SelectedIndex < 0) // None selected yet, select the first
            {
                if (Count > 0)
                    this[0].Focus();
            }
            else
            {
                if (SelectedIndex < Count) // TODO: LOW - For some reason, sometimes, the SelectedIndex refers to a ListItem that disappeared without this index being cleared
                    this[SelectedIndex].Focus();
                if (deselectItem)
                    SelectedIndex = -1; // Deselect
            }
	    }


        /// <summary>
        /// Determines if the specified item is (or is eligible to be) its own container. 
        /// </summary>
        /// <param name="item">The item to check.</param>
        /// <returns>Returns true if the item is (or is eligible to be) its own container; otherwise, false.</returns> 
		protected virtual /*override*/ bool IsItemItsOwnContainerOverride(object item) 
        {
            return (item is ListItem); 
        }

        /// <summary> 
        /// Creates or identifies the element that is used to display the given item.
        /// </summary>
        /// <returns>The element that is used to display the given item.</returns> 
		protected virtual /*override*/ ListItem GetContainerForItemOverride() 
        {
            return _entityListItems.Count == 0 ? new ListItem() : _entityListItems.Pop();
        }
 
        /// <summary>
        /// Prepares the specified element to display the specified item.
        /// </summary> 
        /// <param name="element">Element used to display the specified item.</param> 
        /// <param name="item">Specified item.</param>
		protected virtual /*override*/ void PrepareContainerForItemOverride(DependencyObject element, IEntity item) 
        {
//            base.PrepareContainerForItemOverride(element, item);
            var listItem = element as ListItem;
			Debug.Assert(null != listItem);
            // Prepare the ListItem state
			listItem.ParentListView = this;
            // Prepare the Entity wrapper 
/*            bool setContent = true;
/            if (entityListItem != item) */
            {
/*                // If not a ListItem, propagate the ListView's ItemTemplate
                if (null != ItemTemplate) 
                {
                    // ItemsControl owns recreating containers if ItemTemplate ever changes
                    entityListItem.ContentTemplate = ItemTemplate;
                } 
#if !WPF
                else if (!string.IsNullOrEmpty(DisplayMemberPath)) 
                {
                    // Create a binding for displaying the DisplayMemberPath (which always renders as a string)
                    Binding binding = new Binding(DisplayMemberPath);
                    binding.Converter = new DisplayMemberValueConverter();
                    entityListItem.SetBinding(ContentControl.ContentProperty, binding);
                    setContent = false;
                } 
#endif*/
                // Push the item into the ListItem container 
				listItem.Entity = item;
/*                if (setContent)
                { 
                    entityListItem.Content = item;
                }*/
				_objectToEntityListItem[item] = listItem;
            }
/*            // Apply ItemContainerStyle
            if ((null != ItemContainerStyle) && (null == entityListItem.Style)) 
            {
                // Silverlight does not support cascading styles, so only use ItemContainerStyle
                // if a style is not already set on the ListItem 
                entityListItem.Style = ItemContainerStyle;
            }*/
            // If IsSelected, select the new item 
			if (listItem.IsSelected) 
            {
				SelectedItem = /*listItem.Item;??*/ listItem;
            }
            // If necessary, update an invalidated SelectedIndex (but do not fire SelectionChanged)
            else if (-1 != SelectedIndex) 
            {
                int trueSelectedIndex = IndexOf(SelectedItem);
                if (trueSelectedIndex != SelectedIndex) 
                { 
                    try
                    { 
                        _processingSelectionPropertyChange = true;
                        SelectedIndex = IndexOf(SelectedItem);
                    } 
                    finally
                    {
                        _processingSelectionPropertyChange = false;
                    } 
                }
            } 
        }

        /// <summary> 
        /// Undoes the effects of PrepareContainerForItemOverride.
        /// </summary>
        /// <param name="element">The container element.</param> 
        /// <param name="item">The item.</param> 
        protected virtual /*override*/ void ClearContainerForItemOverride(DependencyObject element, IEntity item)
        { 
//            base.ClearContainerForItemOverride(element, item);
            var listItem = element as ListItem;
			Debug.Assert(null != listItem);
#if !WPF
            // Silverlight bug workaround
            if (null == item) 
            {
				item = listItem.Entity;// (null == entityListItem.Item) ? entityListItem : entityListItem.Item;
            } 
#endif
            // If necessary, unselect the selected item that is being removed
			if ((/*listItem.Item ??*/ listItem) == SelectedItem) 
            {
                SelectedItem = null;
            	SelectedIndex = -1; // TODO: I have added this because it isn't automatically done; why? (investigate other possible bugs)
            }
            // Clear the ListItem state
            listItem.Clear();
//            if (entityListItem != item)
            {
                Debug.Assert(_objectToEntityListItem.ContainsKey(item));
                _objectToEntityListItem.Remove(item);
            }
            ItemsHost.RemoveState(listItem);
            _entityListItems.Push(listItem); // Put back in the cache
        } 
 
        /*
        /// <summary> 
        /// Invoked when the Items property changes.
        /// </summary>
        /// <param name="e">Information about the change.</param> 
        /// <remarks>Not supported by Silverlight. When this is supported,
        /// the workarounds in PrepareContainerForItemOverride and
        /// ClearContainerForItemOverride can be removed.</remarks> 
        protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e) 
        {
            base.OnItemsChanged(e);
            switch (e.Action)
            {
                case NotifyCollectionChangedAction.Add: 
                    if (e.NewStartingIndex <= SelectedIndex)
                    {
                        try 
                        { 
                            _processingSelectionPropertyChange = true;
                            SelectedIndex = Items.IndexOf(SelectedItem);
                        }
                        finally
                        { 
                            _processingSelectionPropertyChange = false;
                        }
                    } 
                    break;
                case NotifyCollectionChangedAction.Remove:
                    if (e.OldItems.Contains(SelectedItem)) 
                    {
                        SelectedItem = null;
                    } 
                    break;
                case NotifyCollectionChangedAction.Reset:
                    SelectedIndex = -1;
                    break;
            }
        } 
        */

        /// <summary> 
        /// Called when the control got focus.
        /// </summary>
        /// <param name="e">The event data.</param> 
        protected override void OnGotFocus(RoutedEventArgs e)
        {
            base.OnGotFocus(e);
            SetIsSelectionActive(this, true);
        }

        /// <summary> 
        /// Called when the control lost focus.
        /// </summary>
        /// <param name="e">The event data.</param> 
        protected override void OnLostFocus(RoutedEventArgs e) 
        {
            base.OnLostFocus(e);
            SetIsSelectionActive(this, false);
            if (_suppressNextLostFocus)
            {
                // Suppressed 
                _suppressNextLostFocus = false;
            }
            else 
            { 
                // Focus is leaving the ListView;stop tracking the previous ListItem
                _listItemOldFocus = null;
            }
        }

        public void SetSelectedItemByEntity(IEntity entity)
        {
            SelectedItem = entity == null ? null : GetListItemForObject(entity); // TODO: LOW - Avoid calling Focus(); causes SL to sometimes crashes?
        }
 
        /// <summary>
        /// Selects the specified item in response to user input.
        /// </summary> 
        /// <param name="item">Item from the Items collection.</param> 
        private void SetSelectedItem(ListItem item)
        { 
            SelectedItem = item;
            if (null != item)
            {
				ListItem listItem = item;/*as ListItem;
                if (null == listItem)
                { 
                    listItem = _objectToEntityListItem[item];
                }*/
				Debug.Assert(null != listItem);
#if WPF
                Keyboard.Focus(listItem);
#else
				listItem.Focus();
#endif
            } 
        }

        public void ScrollToEntity(IEntity entity)
        {
            ScrollIntoView(GetListItemForObject(entity));
        }

	    /// <summary> 
        /// Causes the object to scroll into view.
        /// </summary>
        /// <param name="item">Object to scroll.</param> 
        private void ScrollIntoView(ListItem item)
        {
            if ((null != ElementScrollViewer) && Items.Contains(item)) 
            { 
                Rect itemsHostRect;
                Rect EntityListItemRect;
                if (!IsOnCurrentPage(item, out itemsHostRect, out EntityListItemRect))
                {
                    /*if (IsVerticalOrientation()) 
                    {*/
                        // Scroll into view vertically (first make the right bound visible, then the left)
                        double verticalOffset = ElementScrollViewer.VerticalOffset;
                        double verticalDelta = 0;
                        if (itemsHostRect.Bottom < EntityListItemRect.Bottom)
                        { 
                            verticalDelta = EntityListItemRect.Bottom - itemsHostRect.Bottom;
                            verticalOffset += verticalDelta;
                            verticalOffset += 5; // TODO: This is a hack (the item isn't fully visisble) - Find a real solution
                        } 
                        if (EntityListItemRect.Top - verticalDelta < itemsHostRect.Top)
                        {
                            verticalOffset -= itemsHostRect.Top - (EntityListItemRect.Top - verticalDelta);
                            verticalOffset -= 5; // TODO: This is a hack (the item isn't fully visisble) - Find a real solution
                        } 
                        ScrollToVerticalOffset(verticalOffset);
                    /*} 
                    else
                    {
                        // Scroll into view horizontally (first make the bottom bound visible, then the top) 
                        double horizontalOffset = ElementScrollViewer.HorizontalOffset;
                        double horizontalDelta = 0;
                        if (itemsHostRect.Right < EntityListItemRect.Right) 
                        { 
                            horizontalDelta = EntityListItemRect.Right - itemsHostRect.Right;
                            horizontalOffset += horizontalDelta;
                        }
                        if (EntityListItemRect.Left - horizontalDelta < itemsHostRect.Left)
                        { 
                            horizontalOffset -= itemsHostRect.Left - (EntityListItemRect.Left - horizontalDelta);
                        }
                        ElementScrollViewer.ScrollToHorizontalOffset(horizontalOffset);
                    } */
                }
            }
        }


	    public event EventHandler Click;
        public event EventHandler DoubleClick;

        internal void NotifyListItemClicked(ListItem listItem)
        {
            var handler = Click;
            if (handler != null)
                handler(listItem, EventArgs.Empty);
        }

        internal void NotifyListItemDoubleClicked(ListItem listItem)
        {
            var handler = DoubleClick;
            if (handler != null)
                handler(listItem, EventArgs.Empty);
        }




        /// <summary> 
        /// Called by ListItem instances when they are clicked.
        /// </summary>
		/// <param name="listItem">The ListItem.</param> 
        internal void NotifyListItemPressed(ListItem listItem) 
        {
			_tabOnceActiveElement = listItem;
			if (listItem.IsSelected)
            {
                if (ModifierKeys.Control == (Keyboard.Modifiers & ModifierKeys.Control)) // Deselect
                {
                    SetSelectedItem(null);
                } 
            } 
            else
            {
				ListItem item = /*listItem.Item ??*/ listItem;
                SetSelectedItem(item);
                ScrollIntoView(item);
            }
        }
 
        /// <summary> 
        /// Called by ListItem instances when they get focus
        /// </summary> 
        /// <param name="listItemNewFocus">ListItem that got focus</param>
        internal void NotifyListItemGotFocus(ListItem listItemNewFocus)
        { 
/*#if !WPF // TODO: Removed because it gets in the way of clicking on ListItem's controls
            // If _tabOnceActiveElement is not set or valid, set it to the first item
            if (((null == _tabOnceActiveElement) || 
                 (this != _tabOnceActiveElement.ParentListView)) && 
                (1 <= Count))
            { 
                _tabOnceActiveElement = this[0]; //GetListItemForObject(Items[0]);
            }
            // If getting focus for something other than a valid _tabOnceActiveElement, pass focus to it 
            if ((null != _tabOnceActiveElement) &&
                (listItemNewFocus != _tabOnceActiveElement))
            { 
                _tabOnceActiveElement.Focus();
                return;
            } 
#endif*/

            // Track the focused index 
            _focusedIndex = IndexOf(/*listItemNewFocus.Item ??*/ listItemNewFocus);

            // Select the focused ListItem iff transitioning from another focused ListItem 
            if (//(null != listItemNewFocus) && 
                (null != _listItemOldFocus) &&
                (this == _listItemOldFocus.ParentListView) && 
                (listItemNewFocus != _listItemOldFocus))
            {
				SelectedItem = /*listItemNewFocus.Item ??*/ listItemNewFocus;
            }
            _listItemOldFocus = null;
        } 
 
        /// <summary>
        /// Called by ListItem instances when they lose focus 
        /// </summary>
		/// <param name="listItemOldFocus">ListItem that lost focus</param>
        internal void NotifyListItemLostFocus(ListItem listItemOldFocus) 
        {
            // Stop tracking state
            _focusedIndex = -1;
			_listItemOldFocus = listItemOldFocus;
        }
 
        /// <summary>
        /// Responds to a list box selection change by raising a SelectionChanged event.
        /// </summary> 
        /// <param name="e">Provides data for SelectionChangedEventArgs.</param>
        protected virtual void OnSelectionChanged(SelectionChangedEventArgs e)
        { 
            SelectionChangedEventHandler handler = SelectionChanged;
            if (null != handler)
            { 
                handler(this, e);
            }
        } 

        /// <summary>
        /// Responds to the KeyDown event. 
        /// </summary> 
        /// <param name="e">Provides data for KeyEventArgs.</param>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification="Straightforward switch-based key handling method that barely triggers the warning")] 
        private void ProcessKeyDown(KeyEventArgs e)
        {
            if (e.Handled)
                return;
            bool handled = false;
            int newFocusedIndex = -1;
            switch (e.Key) 
            {
                case Key.Space: 
                case Key.Enter:
                    // TODO: if ((Key.Enter != e.Key) || KeyboardNavigation.GetAcceptsReturn(this))
                    {
                        if (ModifierKeys.Alt != (Keyboard.Modifiers & (ModifierKeys.Control | ModifierKeys.Alt)))
                        {
						    var focusedListItem = FocusManager.GetFocusedElement() as ListItem;
						    if (null != focusedListItem) 
                            {
							    if ((ModifierKeys.Control == (Keyboard.Modifiers & ModifierKeys.Control))
								    && focusedListItem.IsSelected)
                                { 
                                    SetSelectedItem(null);
                                }
                                else
                                {
								    SetSelectedItem(/*listItem.Item;??*/ focusedListItem);
                                } 
                                handled = true;
                            }
                        }
                    }
                    break;
                case Key.Home: 
                    newFocusedIndex = 0;
                    break;
                case Key.End: 
                    newFocusedIndex = Count - 1;
                    break;
                case Key.PageUp: 
                    newFocusedIndex = NavigateByPage(false);
                    break;
                case Key.PageDown: // TODO: These keys don't work well due to virtualization (the new child isn't attached yet to receive focus)
                    newFocusedIndex = NavigateByPage(true);
					break;
				case Key.Left:
				case Key.Up:
				case Key.Right:
				case Key.Down:
				{
					// Compute the newFocusedIndex
					var focusedListItem = FocusManager.GetFocusedElement() as ListItem;
					int row;
					int col;
					if (ItemsHost.GetLocationOfChild(focusedListItem, out row, out col))
					{
						if (e.Key == Key.Left) col--;
						if (e.Key == Key.Up) row--;
						if (e.Key == Key.Right) col++;
						if (e.Key == Key.Down) row++;
						var newFocusedItem = ItemsHost.GetChildAtLocation(row, col) as ListItem;
						if (newFocusedItem != null)
							newFocusedIndex = IndexOf(newFocusedItem);
					}
					else if (FocusManager.GetFocusedElement() == this)
						ElementScrollViewer.ScrollToVerticalOffset(0); // NavigateToStart
                    handled = true;
					break;
				}
                // case Key.Divide:  // Feature only used by SelectionMode.Extended 
                // case Key.Oem2:  // Key not supported by Silverlight
                //    break;
                // case Key.Oem5:  // Key not supported by Silverlight
                //     break;
                default: 
                    Debug.Assert(!handled);
                    break;
            } 
            if ((-1 != newFocusedIndex) && 
                (-1 != _focusedIndex) &&
                (newFocusedIndex != _focusedIndex) && 
                (0 <= newFocusedIndex) &&
                (newFocusedIndex < Count))
            { 
                // A key press will change the focused ListItem
                ListItem listItem = this[newFocusedIndex];
				Debug.Assert(null != listItem);
				_tabOnceActiveElement = listItem;
				ScrollIntoView(/*listItem.Item;??*/ listItem);
                _suppressNextLostFocus = true;
                // TODO: Multiple selection: if ((ModifierKeys.Control == (Keyboard.Modifiers & ModifierKeys.Control))
				listItem.Focus();
                handled = true;
            } 
            if (handled)
            {
                e.Handled = true;
            }
        }
/*
        /// <summary>
        /// Call ElementScrollViewer.ScrollInDirection if possible. 
        /// </summary>
        /// <param name="key">Key corresponding to the direction.</param>
        private void ElementScrollViewerScrollInDirection(Key key) 
        { 
            if (null != ElementScrollViewer)
            { 
                ElementScrollViewer.ScrollInDirection(key);
            }
        } */

        /// <summary>
        /// Responds to the CollectionChanged event for SelectedItems 
        /// </summary> 
        /// <param name="sender">Source of the event.</param>
        /// <param name="e">Provides data for NotifyCollectionChangedEventArgs.</param> 
        private void OnSelectedItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (!_processingSelectionPropertyChange) 
            {
                throw new InvalidOperationException("Resource.EntityListView_OnSelectedItemsCollectionChanged_WrongMode");
            } 
        } 

        /// <summary> 
        /// Implements the SelectedIndexProperty PropertyChangedCallback.
        /// </summary>
        /// <param name="d">The DependencyObject for which the property changed.</param> 
        /// <param name="e">Provides data for DependencyPropertyChangedEventArgs.</param>
        private static void OnSelectedIndexChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        { 
            var EntityListView = d as ListView;
            Debug.Assert(null != EntityListView);
            Debug.Assert(typeof(int).IsInstanceOfType(e.OldValue));
            Debug.Assert(typeof(int).IsInstanceOfType(e.NewValue));
            EntityListView.OnSelectedIndexChanged((int)e.OldValue, (int)e.NewValue);
        } 

        /// <summary>
        /// Called when the SelectedIndex property has changed. 
        /// </summary> 
        /// <param name="oldValue">The value of the property before the change.</param>
        /// <param name="newValue">The value of the property after the change.</param> 
        protected virtual void OnSelectedIndexChanged(int oldValue, int newValue)
        {
			ListItem oldValueItem = ((-1 != oldValue) && (oldValue < Count)) ? this[oldValue] : null;
			ListItem newValueItem = (-1 != newValue) ? this[newValue] : null;
            ProcessSelectionPropertyChange(SelectedIndexProperty, oldValueItem, newValueItem);
        } 
 
        /// <summary>
        /// Implements the SelectedItemProperty PropertyChangedCallback. 
        /// </summary>
        /// <param name="d">The DependencyObject for which the property changed.</param>
        /// <param name="e">Provides data for DependencyPropertyChangedEventArgs.</param> 
        private static void OnSelectedItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var listView = d as ListView;
			Debug.Assert(null != listView);
			listView.OnSelectedItemChanged((ListItem)e.OldValue, (ListItem)e.NewValue);
        } 

        /// <summary>
        /// Called when the SelectedItem property has changed. 
        /// </summary>
        /// <param name="oldValue">The value of the property before the change.</param>
        /// <param name="newValue">The value of the property after the change.</param> 
		protected virtual void OnSelectedItemChanged(ListItem oldValue, ListItem newValue) 
        {
            ProcessSelectionPropertyChange(SelectedItemProperty, oldValue, newValue);
        }

        /// <summary> 
        /// Implements the SelectedItemsProperty PropertyChangedCallback.
        /// </summary>
        /// <param name="d">The DependencyObject for which the property changed.</param> 
        /// <param name="e">Provides data for DependencyPropertyChangedEventArgs.</param> 
        private static void OnSelectedItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        { 
            var EntityListView = d as ListView;
            Debug.Assert(null != EntityListView);
            Debug.Assert(typeof(IList).IsInstanceOfType(e.OldValue) || (null == e.OldValue));
            Debug.Assert(typeof(IList).IsInstanceOfType(e.NewValue) || (null == e.NewValue));
            EntityListView.OnSelectedItemsChanged((IList)e.OldValue, (IList)e.NewValue);
        } 
 
        /// <summary>
        /// Perform the actions necessary to handle a selection property change. 
        /// </summary>
        /// <param name="changedProperty">Selection property that changed.</param>
        /// <param name="oldValue">Old value of the property.</param> 
        /// <param name="newValue">New value of the property.</param>
		private void ProcessSelectionPropertyChange(DependencyProperty changedProperty, ListItem oldValue, ListItem newValue)
        { 
            // Avoid recursion 
            if (_processingSelectionPropertyChange)
				return;
            try
            {
                _processingSelectionPropertyChange = true;

                // Trace the removed/added items for SelectionChanged
				var removedItems = new List<ListItem>();
				var addedItems = new List<ListItem>();

                // If old value present, update the associated ListItem 
                if (null != oldValue)
                {
                    ListItem oldListItem = GetListItemForObject(oldValue);
                    if (null != oldListItem)
                    {
                        oldListItem.IsSelected = false;
                    } 
                    removedItems.Add(oldValue);
                }

                // If new value present, update the associated ListItem
                ListItem newSelectedItem = null;
                int newSelectedIndex = -1;
                if (null != newValue)
                { 
                    ListItem newListItem = GetListItemForObject(newValue);
                    if (null != newListItem)
                    { 
                        newListItem.IsSelected = true;
                    }
                    newSelectedItem = newValue;
                    newSelectedIndex = IndexOf(newSelectedItem);
                    addedItems.Add(newValue);
                } 

                // Update the *other* associated ListView properties
                if (SelectedIndexProperty != changedProperty) 
                {
                    SelectedIndex = newSelectedIndex;
                } 
                if (SelectedItemProperty != changedProperty)
                {
                    SelectedItem = newSelectedItem;
                } 
                SelectedItems.Clear();
                if (-1 != newSelectedIndex) 
                {
                    SelectedItems.Add(newValue);
				}

                // Notify of SelectionChanged
                OnSelectionChanged(
					new SelectionChangedEventArgs(removedItems, addedItems));
            }
            finally 
            {
                _processingSelectionPropertyChange = false;
            }
        }

		/// <summary>
        /// Called when the SelectedItems property has changed.
        /// </summary> 
        /// <param name="oldValue">The value of the property before the change.</param>
        /// <param name="newValue">The value of the property after the change.</param>
        protected virtual void OnSelectedItemsChanged(IList oldValue, IList newValue) 
        { 
            if (null != oldValue)
            { 
                throw new InvalidOperationException("Resource.EntityListView_OnSelectedItemsChanged_ReadOnly");
            }
        } 
/*
        /// <summary>
        /// Implements the SelectionModeProperty PropertyChangedCallback. 
        /// </summary> 
        /// <param name="d">The DependencyObject for which the property changed.</param>
        /// <param name="e">Provides data for DependencyPropertyChangedEventArgs.</param> 
        private static void OnSelectionModeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ListView ListView = d as ListView;
            Debug.Assert(null != ListView);
            Debug.Assert(typeof(SelectionMode).IsInstanceOfType(e.OldValue));
            Debug.Assert(typeof(SelectionMode).IsInstanceOfType(e.NewValue));
            ListView.OnSelectionModeChanged((SelectionMode)e.OldValue, (SelectionMode)e.NewValue);
        }
 
        /// <summary>
        /// Called when the SelectionMode property has changed.
        /// </summary> 
        /// <param name="oldValue">The value of the property before the change.</param>
        /// <param name="newValue">The value of the property after the change.</param>
        protected virtual void OnSelectionModeChanged(SelectionMode oldValue, SelectionMode newValue) 
        { 
            if (SelectionMode.Single != newValue)
            { 
                throw new ArgumentException("Resource.EntityListView_OnSelectionModeChanged_OnlySingleSelection");
            }
        } 

        /// <summary>
        /// Implements the ItemContainerStyleProperty PropertyChangedCallback. 
        /// </summary> 
        /// <param name="d">The DependencyObject for which the property changed.</param>
        /// <param name="e">Provides data for DependencyPropertyChangedEventArgs.</param> 
        private static void OnItemContainerStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ListView ListView = d as ListView;
            Debug.Assert(null != ListView);
            Debug.Assert(typeof(Style).IsInstanceOfType(e.OldValue) || (null == e.OldValue));
            Debug.Assert(typeof(Style).IsInstanceOfType(e.NewValue) || (null == e.NewValue));
            ListView.OnItemContainerStyleChanged((Style)e.OldValue, (Style)e.NewValue);
        }*/
 
        /// <summary>
        /// Called when the ItemContainerStyle property has changed.
        /// </summary> 
        /// <param name="oldItemContainerStyle">The value of the property before the change.</param>
        /// <param name="newItemContainerStyle">The value of the property after the change.</param>
        protected virtual void OnItemContainerStyleChanged(Style oldItemContainerStyle, Style newItemContainerStyle) 
        {
			foreach (ListItem item in Items)
            { 
                ListItem listItem = GetListItemForObject(item);
				if (null != listItem)  // May be null if GetContainerForItemOverride has not been called yet
                {
					if ((null == listItem.Style) || (oldItemContainerStyle == listItem.Style))
                    {
                        // Silverlight does not support cascading styles, so only use the new value 
                        // if it will replace the old value 
#if !WPF
						if (null != listItem.Style) 
                        {
                            throw new NotSupportedException("Resource.EntityListView_OnItemContainerStyleChanged_CanNotSetStyle");
                        } 
#endif
						listItem.Style = newItemContainerStyle;
                    } 
                } 
            }
        } 

        /// <summary>
        /// Implements the IsSelectionActive PropertyChangedCallback. 
        /// </summary>
        /// <param name="d">The DependencyObject for which the property changed.</param>
        /// <param name="e">Provides data for DependencyPropertyChangedEventArgs.</param> 
        private static void OnIsSelectionActiveChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
        {
            var EntityListView = d as ListView;
            Debug.Assert(null != EntityListView);
            Debug.Assert(typeof(bool).IsInstanceOfType(e.OldValue));
            Debug.Assert(typeof(bool).IsInstanceOfType(e.NewValue));
            EntityListView.OnIsSelectionActiveChanged((bool)e.OldValue, (bool)e.NewValue);
        }
 
        /// <summary> 
        /// Called when the IsSelectionActive property has changed.
        /// </summary> 
        /// <param name="oldValue">The value of the property before the change.</param>
        /// <param name="newValue">The value of the property after the change.</param>
        protected virtual void OnIsSelectionActiveChanged(bool oldValue, bool newValue) 
        {
            if (_readOnlyDependencyPropertyChangesAllowed)
            { 
                if (null != SelectedItem) 
                {
                    ListItem selectedListItem = GetListItemForObject(SelectedItem);
                    if (null != selectedListItem)
                    {
                        selectedListItem.ChangeVisualState(); // TODO: Shouldn't be called directly! Find why an event in ListItem doesn't do it
                    }
                }
            } 
            else 
            {
                throw new InvalidOperationException("Resource.EntityListView_OnIsSelectionActiveChanged_ReadOnly");
            }
        }
 
        /// <summary>
        /// Gets the ListItem corresponding to the specified item.
        /// </summary> 
        /// <param name="value">The item being looked up.</param> 
        /// <returns>Corresponding ListItem.</returns>
        private ListItem GetListItemForObject(object value) 
        {
            var selectedEntityListItem = value as ListItem;
            if (null == selectedEntityListItem) 
            {
                _objectToEntityListItem.TryGetValue((IEntity)value, out selectedEntityListItem);
            }
            return selectedEntityListItem;
        }
 /*
        /// <summary>
        /// Indicate whether the orientation of the ListView's items is vertical.
        /// </summary> 
        /// <returns>True if the orientation is vertical;false otherwise.</returns>
        private bool IsVerticalOrientation()
        { 
            StackPanel stackPanel = ItemsHost as StackPanel;
            return (null == stackPanel) ? true : (stackPanel.Orientation == Orientation.Vertical);
        } */

        /// <summary>
        /// Indicate whether the specified item is currently visible. 
        /// </summary>
        /// <param name="item">The item.</param>
        /// <returns>True if the item is visible;false otherwise.</returns> 
        /// <remarks>Similar to WPF's corresponding ItemsControl method.</remarks> 
		private bool IsOnCurrentPage(ListItem item)
        { 
            Rect itemsHostRect;
            Rect entityListItemRect;
            return IsOnCurrentPage(item, out itemsHostRect, out entityListItemRect);
        }

        /// <summary> 
        /// Indicate whether the specified item is currently visible. 
        /// </summary>
        /// <param name="item">The item.</param> 
        /// <param name="itemsHostRect">Rect for the item host element.</param>
        /// <param name="listItemRect">Rect for the ListItem element.</param>
        /// <returns>True if the item is visible;false otherwise.</returns> 
        /// <remarks>Similar to WPF's corresponding ItemsControl method.</remarks>
        private bool IsOnCurrentPage(ListItem item, out Rect itemsHostRect, out Rect listItemRect)
        { 
            ListItem listItem = GetListItemForObject(item);
			Debug.Assert(null != listItem);
            // Get Rect for item host element 
			var itemsHost = ElementScrollContentPresenter;
/*                (null != ElementScrollViewer) ?
                    ((null != ElementScrollViewer.ElementScrollContentPresenter) ? ElementScrollViewer.ElementScrollContentPresenter as FrameworkElement : ElementScrollViewer as FrameworkElement) : 
                    ItemsHost;*/
            Debug.Assert(null != itemsHost);
            itemsHostRect = new Rect(new Point(), new Point(itemsHost.RenderSize.Width, itemsHost.RenderSize.Height));
            // Adjust Rect to account for padding 
            var itemsHostControl = itemsHost as Control;
            if (null != itemsHostControl) 
            {
                Thickness padding = itemsHostControl.Padding;
                itemsHostRect = new Rect( 
                    itemsHostRect.Left + padding.Left,
                    itemsHostRect.Top + padding.Top,
                    itemsHostRect.Width - padding.Left - padding.Right, 
                    itemsHostRect.Height - padding.Top - padding.Bottom);
            }
            // Get relative Rect for ListItem 
            try
            {
                var generalTransform = listItem.TransformToVisual(itemsHost);
                listItemRect = new Rect(
                    generalTransform.Transform(new Point()),
                    generalTransform.Transform(new Point(
                        listItem.RenderSize.Width,
                        listItem.RenderSize.Height)));
            }
            catch // => The ListItem isn't currently attached to the ItemsHost.Children (due to virtualization)
            {
                var r = ItemsHost.GetElementCurrentRect(listItem);
                if (r == Rect.Empty)
                {
                    listItemRect = r; // TODO: Confirm that it will never happen and throw an exception
                    return true;
                }
                listItemRect = new Rect(r.X + 5, r.Y + 5 - ElementScrollViewer.VerticalOffset, r.Width, r.Height); // TODO: Confirm that it is always correct + Why add "5"?
            }
            // Return result 
            return //(IsVerticalOrientation() ?
                (itemsHostRect.Top <= listItemRect.Top) && (listItemRect.Bottom <= itemsHostRect.Bottom) // :
                && (itemsHostRect.Left <= listItemRect.Left) && (listItemRect.Right <= itemsHostRect.Right);
        } 

        /// <summary> 
        /// Get the first visible item.
        /// </summary>
        /// <param name="startingIndex">Starting index to search from.</param> 
        /// <param name="forward">Search forward if true;backward otherwise.</param>
        /// <returns>Index of first visible item.</returns>
        /// <remarks>Similar to WPF's corresponding ItemsControl method.</remarks> 
        private int GetFirstItemOnCurrentPage(int startingIndex, bool forward) 
        {
            int delta = (forward ? 1 : -1);
            int firstItemOnCurrentPage = -1;
            int probeIndex = startingIndex;
            // Scan looking for the first visible element
			while ((0 <= probeIndex) && (probeIndex < Items.Count))
            {
                firstItemOnCurrentPage = probeIndex;
                if (IsOnCurrentPage(this[probeIndex]))
                    break;
                probeIndex += delta;
            }
            // Then scan looking for the last visible element
            if (!forward) // TODO: LOW - What is the scenario where we go backward? And the meaning of "first" in that case
                while ((0 <= probeIndex) && (probeIndex < Items.Count) && IsOnCurrentPage(this[probeIndex]))
                {
                    firstItemOnCurrentPage = probeIndex;
                    probeIndex += delta;
                }
            return firstItemOnCurrentPage;
        }

        /// <summary> 
        /// Get the first visible entity.
        /// </summary>
        public IEntity GetFirstVisibleEntity()
        {
            var index = GetFirstItemOnCurrentPage(0, true);
            if (index < 0 || !IsOnCurrentPage(this[index]))
                return null;
            return this[index].Entity;
        }

        public IEntity GetEntityBefore(IEntity entity)
        {
            var index = _displayedList.IndexOf(entity);
            return index <= 0 ? null : _displayedList[index - 1];
        }

        public Rect GetLocationByEntity(IEntity entity)
        {
            var listItem = GetListItemForObject(entity);
            return ItemsHost.GetElementCurrentRect(listItem); // TODO: The other option doesn't work well due to virtualization (but this should be ok based on the scenario in which it is used)
            /*/ Get relative Rect for ListItem
            var generalTransform = listItem.TransformToVisual(ItemsHost);
            return new Rect(
                generalTransform.Transform(new Point()),
                generalTransform.Transform(new Point(
                    listItem.RenderSize.Width,
                    listItem.RenderSize.Height)));*/
        }

        /// <summary> 
        /// Move the focus forward/backward one page.
        /// </summary>
        /// <param name="forward">Forward if true;backward otherwise</param> 
        /// <returns>New focused index.</returns>
        /// <remarks>Similar to WPF's corresponding ItemsControl method.</remarks>
        private int NavigateByPage(bool forward) 
        {
			if (Count == 0)
				return -1;

			var focusedListItem = FocusManager.GetFocusedElement() as ListItem ?? this[0];
        	int newFocusedIndex = -1;
			int row;
			int col;
			if (ItemsHost.GetLocationOfChild(focusedListItem, out row, out col))
			{
				int delta = forward ? 1 : -1;
				int originalRow = row;
                row += delta * 4; // TODO: NumberOfRowsFullyVisible;
				ListItem newFocusedItem = null;
				while (row != originalRow) // As long as we are not back on the original row (which would mean: Border reached)
				{
					// Look for the item right outside the page of the current one)
					newFocusedItem = ItemsHost.GetChildAtLocation(row, col) as ListItem;
					if (newFocusedItem != null)
						break; // Found
					row -= delta; // If we went too far, try closer
				}

				if (newFocusedItem == null) // Border reached, go to the first/last item
					newFocusedItem = forward ? this[Count-1] : this[0];

				newFocusedIndex = IndexOf(newFocusedItem);
			}
        	return newFocusedIndex;

/*			ListItem item = (-1 != _focusedIndex) ? this[_focusedIndex] : null;
            // Get it visible to start with
            if ((null != item) && !IsOnCurrentPage(item))
            { 
                ScrollIntoView(item);
                if (null != ElementScrollViewer)
                { 
                    ElementScrollViewer.UpdateLayout();
                }
            } 
            // Inlined implementation of NavigateByPageInternal
            int newFocusedIndex;
            if (null == item)
            { 
                // Select something
                newFocusedIndex = GetFirstItemOnCurrentPage(_focusedIndex, forward);
            } 
            else 
            {
                int firstItemOnCurrentPage = GetFirstItemOnCurrentPage(_focusedIndex, forward);
                if (firstItemOnCurrentPage != _focusedIndex)
                {
                    // Select the "edge" element 
                    newFocusedIndex = firstItemOnCurrentPage;
                }
                else 
                { 
                    if (null != ElementScrollViewer)
                    { 
                        // Scroll a page in the relevant direction
                        /*if (IsVerticalOrientation())
                        { /
                            ElementScrollViewer.ScrollToVerticalOffset(Math.Max(0, Math.Min(ElementScrollViewer.ScrollableHeight,
                                ElementScrollViewer.VerticalOffset + (ElementScrollViewer.ViewportHeight * (forward ? 1 : -1)))));
                        /*} 
                        else 
                        {
                            ElementScrollViewer.ScrollToHorizontalOffset(Math.Max(0, Math.Min(ElementScrollViewer.ScrollableWidth, 
                                ElementScrollViewer.HorizontalOffset + (ElementScrollViewer.ViewportWidth * (forward ? 1 : -1)))));
                        }/
                        ElementScrollViewer.UpdateLayout();
                    }
                    // Select the "edge" element
                    newFocusedIndex = GetFirstItemOnCurrentPage(_focusedIndex, forward);
                } 
            }
            return newFocusedIndex;*/
        }




        private void ScrollToVerticalOffset(double verticalOffset)
        {
            ElementScrollViewer.ScrollToVerticalOffset(verticalOffset);

            RaiseVerticalScroll(this, new ScrollEventArgs(
                ScrollEventType.ThumbPosition, verticalOffset));
        }


	    private bool _registered;

        private void RegisterVerticalScroll()
        {
            if (_registered)
                return;

            var verticalScrollBar = GetVerticalScrollBar(ElementScrollViewer);
            if (verticalScrollBar == null)
                return;

            verticalScrollBar.Scroll += RaiseVerticalScroll;
            _registered = true;
        }


        private static ScrollBar GetVerticalScrollBar(DependencyObject obj)
        {
            int count = System.Windows.Media.VisualTreeHelper.GetChildrenCount(obj);
            for (int i = 0; i < count; i++)
            {
                DependencyObject child = System.Windows.Media.VisualTreeHelper.GetChild(obj, i);
                var scrollBar = child as ScrollBar;
                if (scrollBar == null)
                {
                    var verticalScrollBar = GetVerticalScrollBar(child);
                    if (verticalScrollBar != null)
                        return verticalScrollBar;
                }
                else if (scrollBar.Name == "VerticalScrollBar") // => Found
                    return scrollBar;
            }
            return null;
	    }


	    private void RaiseVerticalScroll(object sender, ScrollEventArgs e)
        {
            var handler = VerticalScroll;
            if (handler != null)
                handler(this, e);
        }
    }
}
